
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>

#include "Ennemi.h"


void initEnnemi (Ennemi* pennemi, const TypeEnnemi type_ennemi, const float posX, const float posY, Trajectoire* ptraj)
{
	assert(pennemi!=NULL && posX>=0 && posY>=0 && ptraj!=NULL);
	pennemi->type_ennemi_std=type_ennemi;
	pennemi->posX_ennemi=posX;
	pennemi->posY_ennemi=posY;
	pennemi->ptraj_ennemi=ptraj;
	pennemi->timer_deplacement_arrive=30;
	if(type_ennemi == 0)	//ennemi faible
	{
		pennemi->timer_deplacement_base=20;
		pennemi->timer_deplacement=pennemi->timer_deplacement_base;
		pennemi->timer_tir_base=5;
		pennemi->timer_tir=pennemi->timer_tir_base;
		pennemi->tailleX_ennemi = 2;
		pennemi->tailleY_ennemi = 2;
		pennemi->PV_ennemi = 20;
		
	}
	else if(type_ennemi == 1)	//ennemi fort
	{
		pennemi->timer_deplacement_base=100;
		pennemi->timer_deplacement=pennemi->timer_deplacement_base;
		pennemi->timer_tir_base=3;
		pennemi->timer_tir=pennemi->timer_tir_base;
		pennemi->tailleX_ennemi = 4;
		pennemi->tailleY_ennemi = 4;
		pennemi->PV_ennemi = 50;
	}
	else if(type_ennemi == 2)	//ennemi moyen
	{
		pennemi->timer_deplacement_base=50;
		pennemi->timer_deplacement=pennemi->timer_deplacement_base;
		pennemi->timer_tir_base=4;
		pennemi->timer_tir=pennemi->timer_tir_base;
		pennemi->tailleX_ennemi = 4;
		pennemi->tailleY_ennemi = 4;
		pennemi->PV_ennemi = 40;
	}
	else if(type_ennemi == 3)	//asteroide
	{
		pennemi->timer_deplacement_base=60;
		pennemi->timer_deplacement=pennemi->timer_deplacement_base;
		pennemi->timer_tir_base=4;
		pennemi->timer_tir=pennemi->timer_tir_base;
		pennemi->tailleX_ennemi = 4;
		pennemi->tailleY_ennemi = 4;
		pennemi->PV_ennemi = 3000;
	}
}

Ennemi* creerEnnemi (const TypeEnnemi type_ennemi, const float posX, const float posY, Trajectoire* ptraj)
{
	assert(posX>=0 && posY>=0 && ptraj!=NULL);
	assert(type_ennemi == 0 || type_ennemi == 1);
	Ennemi* pennemi;
	pennemi=(Ennemi*)malloc(sizeof(Ennemi));
	initEnnemi(pennemi, type_ennemi, posX, posY, ptraj);
	return(pennemi);
}

void libereEnnemi (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	detruireTrajectoire(&(pennemi->ptraj_ennemi));
}

void detruireEnnemi (Ennemi** ppennemi)
{
	assert(ppennemi!=NULL);
	libereEnnemi (*ppennemi);
	free (*ppennemi);
	*ppennemi=NULL;
}

void setTimerTir (Ennemi* pennemi, const int timer)
{
	assert(pennemi!=NULL);
	assert(timer >= 0);
	pennemi->timer_tir = timer;
}

int getTimerTir (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return pennemi->timer_tir;
}

void setTimerTirBase (Ennemi* pennemi, const int timer)
{
	assert(pennemi!=NULL);
	assert(timer >= 0);
	pennemi->timer_tir_base = timer;
}

int getTimerTirBase (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return pennemi->timer_tir_base;
}

void setTimerDeplacementArrive (Ennemi* pennemi, const int timer)
{
	assert(pennemi!=NULL);
	assert(timer >= 0);
	pennemi->timer_deplacement_arrive = timer;
}

int getTimerDeplacementArrive (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return pennemi->timer_deplacement_arrive;
}

void setTimerDeplacement (Ennemi* pennemi, const int timer)
{
	assert(pennemi!=NULL);
	assert(timer >= 0);
	pennemi->timer_deplacement = timer;
}

int getTimerDeplacement (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return pennemi->timer_deplacement;
}

void setTimerDeplacementBase (Ennemi* pennemi, const int timer)
{
	assert(pennemi!=NULL && timer >= 0);
	pennemi->timer_deplacement_base = timer;
}

int getTimerDeplacementBase (Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return pennemi->timer_deplacement_base;
}

const TypeEnnemi getTypeEnnemiStd (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->type_ennemi_std);
}

void setTypeEnnemiStd (Ennemi* pennemi, const TypeEnnemi type_ennemi)
{
	assert(pennemi!=NULL);
	assert(type_ennemi == 0 || type_ennemi == 1 || type_ennemi == 2 || type_ennemi == 3);
	pennemi->type_ennemi_std=type_ennemi;
}

const int getPvEnnemi (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->PV_ennemi);
}

void setPvEnnemi (Ennemi* pennemi, const int PV)
{
	assert(pennemi!=NULL && PV>=0);
	pennemi->PV_ennemi=PV;
}

const float getPosXEnnemi (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->posX_ennemi);
}

void setPosXEnnemi (Ennemi* pennemi, const float posX)
{
	assert(pennemi!=NULL && posX>=0);
	pennemi->posX_ennemi=posX;
}

const float getPosYEnnemi (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->posY_ennemi);
}

void setPosYEnnemi (Ennemi* pennemi, const float posY)
{
	assert(pennemi!=NULL && posY>=0);
	pennemi->posY_ennemi=posY;
}

const float getTailleXEnnemi (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->tailleX_ennemi);
}

void setTailleXEnnemi (Ennemi* pennemi, const float tailleX)
{
	assert(pennemi!=NULL && tailleX>0);
	pennemi->tailleX_ennemi=tailleX;
}

const float getTailleYEnnemi (const Ennemi* pennemi)
{
	assert(pennemi!=NULL);
	return (pennemi->tailleY_ennemi);
}

void setTailleYEnnemi (Ennemi* pennemi, const float tailleY)
{
	assert(pennemi!=NULL && tailleY>0);
	pennemi->tailleY_ennemi=tailleY;
}

/** @brief Cette fonction assure la validite d'une position de l'ennemi passe en parametre
 * lors d'un deplacement, elle retourne 0 si la position est valide,1 dans le cas contraire
 * @param [in] pterrain
 * @param [in] pennemi
 * @param [in] deplacementX
 * @param [in] deplacementY*/
const int terEstPositionEnnemiValide (const Terrain* pterrain,Ennemi* pennemi,
	const float deplacementX, const float deplacementY)
{
	assert (pterrain!=NULL && pennemi!=NULL);
	if ((getPosXEnnemi(pennemi)+getTailleXEnnemi(pennemi)+deplacementX<=getDimX_terrain(pterrain))
		&&(getPosYEnnemi(pennemi)+getTailleYEnnemi(pennemi)+deplacementY<=getDimY_terrain(pterrain))
		&&(getPosXEnnemi(pennemi)+deplacementX>=0)
		&& (getPosYEnnemi(pennemi)+deplacementY>=0))
		return 0;
	return 1;
}

void deplacerEnnemi (Ennemi* pennemi, Terrain* pterrain, float defil)
{
	assert(pennemi!=NULL && pterrain!=NULL);
	float t=pennemi->ptraj_ennemi->vitesse1;
	float deplacementX=t*(pennemi->ptraj_ennemi->vectx);
	float deplacementY=t*(pennemi->ptraj_ennemi->vecty);
	if (getTimerDeplacementArrive(pennemi) == 0)
	{
	
		if (terEstPositionEnnemiValide(pterrain, pennemi, deplacementX, deplacementY)==0 && getTimerDeplacement(pennemi) == 0)
		{
			setPosXEnnemi (pennemi, getPosXEnnemi(pennemi)+deplacementX);
			setPosYEnnemi (pennemi, getPosYEnnemi(pennemi)+deplacementY);
		}
		else if(getTimerDeplacement(pennemi) > 0)
		{
			setTimerDeplacement(pennemi,(getTimerDeplacement(pennemi)-1));
			setPosYEnnemi (pennemi, getPosYEnnemi(pennemi)-defil);
		}
	}
	else
	{
		setTimerDeplacementArrive(pennemi,getTimerDeplacementArrive(pennemi)-1);
		if (terEstPositionEnnemiValide(pterrain, pennemi, deplacementX, deplacementY)==0)
		{
			setPosXEnnemi (pennemi, getPosXEnnemi(pennemi)+deplacementX);
			setPosYEnnemi (pennemi, getPosYEnnemi(pennemi)+deplacementY);
		}
	}
}

Tir* tirerEnnemi (Ennemi* pennemi, Terrain* pterrain,Heros* pheros, float defil)
{
	assert(pennemi != NULL && pterrain != NULL && pheros != NULL);
	float dist_heros_ennemi = sqrt((getPosXHeros(pheros)-getPosXEnnemi(pennemi))*(getPosXHeros(pheros)-getPosXEnnemi(pennemi))
					+ (getPosYHeros(pheros)-getPosYEnnemi(pennemi))*(getPosYHeros(pheros)-getPosYEnnemi(pennemi)));
	
	Point* pt1=creerPoint(getPosXEnnemi(pennemi)+0.5*getTailleXEnnemi(pennemi), getPosYEnnemi(pennemi)+getTailleYEnnemi(pennemi));
	Point* pt2=creerPoint(getPosXHeros(pheros)+0.5*getTailleXHeros(pheros),(getPosYHeros(pheros)+(0.5*getTailleYHeros(pheros)))-(dist_heros_ennemi*(defil/2)));
	// Le 2eme point est créé au dessus du héro pour compenser le deplacement due à la monté de la fenetre
	Trajectoire* ptraj=creerTrajectoire(pt1, pt2, 1.3);
	Tir* ptir=creerTir(1, 1, getPosXEnnemi(pennemi)+0.5*getTailleXEnnemi(pennemi), getPosYEnnemi(pennemi)+getTailleYEnnemi(pennemi), ptraj, 1); 
	return ptir;
}

void enleverVieEnnemi (Ennemi* pennemi, const int degat)
{
	assert(pennemi != NULL && degat > 0);
	if (pennemi->PV_ennemi > degat)
		setPvEnnemi(pennemi, getPvEnnemi(pennemi)-degat);
	else
		setPvEnnemi(pennemi, 0);
}

/** @brief Cette procedure permet de tester toutes les fonctions du module*/
void testRegressionEnnemi ()
{
	printf ("on va declarer un ennemi\n\n");	
	Ennemi* pmechant;
	printf ("on va declarer une trajectoire\n\n");	
	Trajectoire* ptraj;
	int pv;
	float tailleX;
	printf ("on va declarer des points\n\n");	
	Point* ppt1;
	Point* ppt2;
	printf ("on va creer des points\n\n");
	ppt1=creerPoint (1.2, 2.2);
	ppt2=creerPoint (2.5, 3.5);
	printf("l adresse des points est %p %p\n\n",ppt1,ppt2);
	printf ("on va creer une trajectoire\n\n");
	ptraj=creerTrajectoire (ppt1, ppt2, 2.00);
	printf("l adresse de la trajectoire est %p et sa vitesse %f et les positions des points sont %f et %f et %f\n\n"
	, ptraj, ptraj->vitesse1, ptraj->ppoint1->posX_point, ptraj->ppoint1->posY_point, ptraj->ppoint2->posY_point);
	printf ("Creation de l'ennemi ouais gros\n");
	pmechant=creerEnnemi (1, 5.75, 10.25, ptraj);
	printf("Creation reussie\n");
	printf("La position X de l'ennemi est censee etre 5.75\n");
	printf("En realite, posX = %f\n", getPosXEnnemi(pmechant));
	setPvEnnemi(pmechant, 500);
	pv=getPvEnnemi(pmechant);
	if (pv!=500)
		printf("Erreur getPv\n");
	else
		printf("getPv reussi\n");
	setTailleXEnnemi(pmechant, 1000);
	tailleX=getTailleXEnnemi(pmechant);
	if (tailleX!=1000)
		printf("Erreur get/setTx\n");
	else
		printf("get/setTx reussi\n");
	enleverVieEnnemi(pmechant, 1);
	printf("L'ennemi a perdu 1 de vie, il lui reste %d\n", getPvEnnemi(pmechant));

	detruireEnnemi(&pmechant);
	printf ("fin du test du module Ennemi\n\n");
}

